{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Using QingYan GLMs API\n",
    "\n",
    "**This tutorial is available in English and is attached below the Chinese explanation**\n",
    "\n",
    "本教程根据[官方文档](https://zhipu-ai.feishu.cn/wiki/X8ykw4IXpieCOxkYxbrcxT9vn5f)进行最基础的演示，旨在让开发者最快上手 GLMs 智能体对话 API。\n",
    "This tutorial provides the most basic demonstration based on [Official Document](https://zhipu-ai.feishu.cn/wiki/X8ykw4IXpieCOxkYxbrcxT9vn5f), aiming to allow developers to get started with the GLMs agent dialogue API as quickly as possible.\n",
    "\n",
    "<span style='color: red; font-weight: bold;'>⚠️ 目前，您只能调用属于自己的智能体，不能调用别人的智能体！ ⚠️</span>\n",
    "\n",
    "<span style='color: red; font-weight: bold;'>⚠️ Currently, you can only call your own GLMs Agent, not other people's ! ⚠️</span>\n",
    "\n",
    "# 1. Get API access token\n",
    "\n",
    "在开始对话之前，我们需要从智谱清言网站获取Access Token，用于进行对话。你可以在[这里](https://chatglm.cn/developersPanel/apiSet)获得你的API Key和API Secret。\n",
    "为避免API调用占用过多资源，系统限制每个开发者（非API_KEY）的并发数量。默认并发数为2。并发限制范围包括上传文件和会话调用API接口。\n",
    "此外，我们对每个开发者调用会话接口的次数也设置了上限，目前为一天500次，总量5000次。\n",
    "\n",
    "Before starting the conversation, we need to obtain the Access Token from the Zhipu Qingyan website for conversation. You can get your API Key and API Secret [here](https://chatglm.cn/developersPanel/apiSet).\n",
    "To prevent API calls from taking up too many resources, the system limits the number of concurrencies for each developer (non-API_KEY). The default number of concurrency is 2. Concurrency limits include uploading files and session calls to API interfaces.\n",
    "In addition, we have also set a limit on the number of times each developer can call the session interface, which is currently 500 times a day and 5,000 times in total."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "9b5826dfda9c2f04"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/zr/Code/glm-cookbook/venv/lib/python3.9/site-packages/urllib3/__init__.py:35: NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "text/plain": "'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcxNTI0NDY2MywianRpIjoiYWRjMTdiNWItMGFlZi00YWU4LTg5ZTEtYjU1NDNhOTFmYWNjIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IkFQSV82NTQxMjhhNzZkNWQzNGJiYjEyODMxMTNfZjJjMjJjYmIiLCJuYmYiOjE3MTUyNDQ2NjMsImV4cCI6MTcxNjEwODY2MywidWlkIjoiNjYzYWU1ZTljN2RiOTZjY2RiNTAzMDVhIiwidXBsYXRmb3JtIjoiIiwicm9sZXMiOlsiYXV0aGVkX3VzZXIiXX0.bieAsD51OrIzZ5fv1Pjau82AsbVad75nMtEFrs-Qn0Q'"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import requests\n",
    "def get_access_token(api_key, api_secret):\n",
    "    url = \"https://chatglm.cn/chatglm/assistant-api/v1/get_token\"\n",
    "    data = {\n",
    "        \"api_key\": api_key,\n",
    "        \"api_secret\": api_secret\n",
    "    }\n",
    "\n",
    "    response = requests.post(url, json=data)\n",
    "    token_info = response.json()\n",
    "    return token_info['result']['access_token']\n",
    "\n",
    "\n",
    "# Here you need to replace the API Key and API Secret with your，I provide a test key and secret here\n",
    "api_key = 'db3615995fd68471' \n",
    "api_secret = 'dd1ad39dc0e12075ddbde0e33825dcb7' \n",
    "token = get_access_token(api_key, api_secret)\n",
    "token"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-09T08:51:03.258831Z",
     "start_time": "2024-05-09T08:51:03.039349Z"
    }
   },
   "id": "224bfbe6a64f7b0d",
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 2. 与智能体进行对话\n",
    "\n",
    "接着，我就可以使用智能体进行对话了。需要注意的是，本代码仅支持使用 SSE 流式输出。在这里，我们仅打印了最后的结果，即完整的输出。请注意，智谱清言的API接口与 OpenAI格式有很大差异，需要开发者自行进行深度开发。\n",
    "这里展现了一个最基础的对话示例，更多的功能和接口请参考[官方文档](https://zhipu-ai.feishu.cn/wiki/X8ykw4IXpieCOxkYxbrcxT9vn5f)。\n",
    "\n",
    "Then, I can use the agent to have a conversation. It should be noted that this code only supports streaming output using SSE. Here, we have printed only the final result, the complete output. Please note that the API interface of Zhipu Qingyan is very different from the OpenAI format and requires developers to conduct in-depth development on their own.\n",
    "A basic dialogue example is shown here. For more functions and interfaces, please refer to [Official Documentation](https://zhipu-ai.feishu.cn/wiki/X8ykw4IXpieCOxkYxbrcxT9vn5f)."
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "3deb1647a5b275e"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "import json\n",
    "import requests\n",
    "\n",
    "def handle_response(data_dict):\n",
    "    message = data_dict.get(\"message\")\n",
    "    if len(message) > 0:\n",
    "        content = message.get(\"content\")\n",
    "        if len(content) > 0:\n",
    "            response_type = content.get(\"type\")\n",
    "            if response_type == \"text\":\n",
    "                text = content.get(\"text\", \"No text provided\")\n",
    "                return f\"{text}\"\n",
    "\n",
    "            elif response_type == \"image\":\n",
    "                images = content.get(\"image\", [])\n",
    "                image_urls = \", \".join(image.get(\"image_url\") for image in images)\n",
    "                return f\"{image_urls}\"\n",
    "\n",
    "            elif response_type == \"code\":\n",
    "                return f\"{content.get('code')}\"\n",
    "\n",
    "            elif response_type == \"execution_output\":\n",
    "                return f\"{content.get('content')}\"\n",
    "\n",
    "            elif response_type == \"system_error\":\n",
    "                return f\"{content.get('content')}\"\n",
    "\n",
    "            elif response_type == \"tool_calls\":\n",
    "                return f\"{data_dict['tool_calls']}\"\n",
    "\n",
    "            elif response_type == \"browser_result\":\n",
    "                content = json.loads(content.get(\"content\", \"{}\"))\n",
    "                return f\"Browser Result - Title: {content.get('title')} URL: {content.get('url')}\"\n",
    "\n",
    "\n",
    "def send_message(assistant_id, access_token, prompt, conversation_id=None, file_list=None, meta_data=None):\n",
    "    url = \"https://chatglm.cn/chatglm/assistant-api/v1/stream\"\n",
    "    headers = {\n",
    "        \"Authorization\": f\"Bearer {access_token}\",\n",
    "        \"Content-Type\": \"application/json\"\n",
    "    }\n",
    "    data = {\n",
    "        \"assistant_id\": assistant_id,\n",
    "        \"prompt\": prompt,\n",
    "    }\n",
    "\n",
    "\n",
    "    if conversation_id:\n",
    "        data[\"conversation_id\"] = conversation_id\n",
    "    if file_list:\n",
    "        data[\"file_list\"] = file_list\n",
    "    if meta_data:\n",
    "        data[\"meta_data\"] = meta_data\n",
    "\n",
    "    with requests.post(url, json=data, headers=headers) as response:\n",
    "        if response.status_code == 200:\n",
    "            for line in response.iter_lines():\n",
    "                if line:\n",
    "                    decoded_line = line.decode('utf-8')\n",
    "                    if decoded_line.startswith('data:'):\n",
    "                        data_dict = json.loads(decoded_line[5:])\n",
    "                        output = handle_response(data_dict)\n",
    "\n",
    "\n",
    "        else:\n",
    "            return \"Request failed\", response.status_code\n",
    "        print(output)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-09T08:51:03.267827Z",
     "start_time": "2024-05-09T08:51:03.260223Z"
    }
   },
   "id": "23e9879d7206cdff",
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我是一个名为zR的程序员，精通Python代码，熟练使用github、huggingface等开源工具。我来自西交利物浦大学，目前大三。我对话题的选择比较挑剔，喜欢深入探讨技术问题，但对基础问题不太感兴趣。我的目标是成为一名算法工程师，并在开源社区做出贡献。我重视独立思考，对于有自己见解的人，我会给予高度尊重并认真沟通。\n"
     ]
    }
   ],
   "source": [
    "# This is the GLMs of zR, only zR's key can call this GLMs\n",
    "\n",
    "assistant_id = \"65f3dab425fab01c6821d461\" \n",
    "access_token = token\n",
    "prompt = \"你是谁\"\n",
    "result = send_message(assistant_id, access_token, prompt)\n",
    "result"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-05-09T08:51:13.809493Z",
     "start_time": "2024-05-09T08:51:03.269687Z"
    }
   },
   "id": "623aa9e8ff979e3f",
   "execution_count": 3
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
